﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Nirvana
{
	/// <summary>
	/// 所有使用一样材质球的对象阴影，在一个Mesh上绘制
	/// </summary>
	[RequireComponent(typeof(MeshFilter),typeof(MeshRenderer))]
	public sealed class SimpleShadowMesh : MonoBehaviour
	{
		private MeshRenderer meshRenderer;
		private Material material;
		private Mesh mesh;
		private Vector3[] vertices;
		private Vector2[] uv;
		private int[] triangles;
		private LinkedList<SimpleShadow> simpleShadowList = new LinkedList<SimpleShadow>();
		/// <summary>
		/// 阴影mesh数量
		/// </summary>
		private int shadowCount;
		private bool isNeedUpdateMesh;

		public Material GetMaterial()
        {
			return this.material;
        }

		public void SetMaterial(Material mat)
        {
			if (this.material != mat)
            {
				this.material = mat;
				if (this.meshRenderer != null) this.meshRenderer.sharedMaterial = this.material;
            }
        }

		public LinkedListNode<SimpleShadow> Add(SimpleShadow shadow)
        {
			this.isNeedUpdateMesh = true;
			return this.simpleShadowList.AddLast(shadow);
        }

		public void Remove(LinkedListNode<SimpleShadow> list)
        {
			this.isNeedUpdateMesh = true;
			this.simpleShadowList.Remove(list);
        }

		void Awake()
        {
			MeshFilter filter = GetComponent<MeshFilter>();
			if (filter.mesh == null) filter.mesh = new Mesh();

			this.mesh = filter.mesh;
			this.mesh.name = "Shadow Mesh";
			this.GenterVector(32);
			this.meshRenderer = GetComponent<MeshRenderer>();
			if(this.meshRenderer != null)
            {
				this.meshRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
				this.meshRenderer.receiveShadows = false;
				this.meshRenderer.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off;
				this.meshRenderer.sharedMaterial = this.material;
            }

        }

		private void Update()
        {
			this.GenterVector(this.simpleShadowList.Count);
            if (!this.isNeedUpdateMesh)
            {
				//检测那些材质球阴影有更新
				LinkedListNode<SimpleShadow> next;
				for(LinkedListNode<SimpleShadow> linkednode = this.simpleShadowList.First;linkednode != null; linkednode = next)
                {
					next = linkednode.Next;
					var shadow = linkednode.Value;
					if (shadow.IsNeedShow)
					{
						this.isNeedUpdateMesh = true;
						break;
					}
				}
            }

			if (this.isNeedUpdateMesh)
			{
				int vertexCount = 0;
				LinkedListNode<SimpleShadow> next2;
				for (LinkedListNode<SimpleShadow> linkedListNode2 = this.simpleShadowList.First; linkedListNode2 != null; linkedListNode2 = next2)
				{
					next2 = linkedListNode2.Next;
					var shadow = linkedListNode2.Value;
					if (shadow.InCameraViewBound)
					{
						shadow.GenterVector(this.vertices, this.uv, vertexCount);
						vertexCount++;
					}
					shadow.IsNeedShow = false;
				}
				this.mesh.vertices = this.vertices;
				this.mesh.uv = this.uv;
				int num2 = 6 * vertexCount;
				if (this.triangles == null || this.triangles.Length != num2)
				{
					this.triangles = new int[6 * vertexCount];
				}
				for (int i = 0; i < vertexCount; i++)
				{
					int startIndex = 6 * i;
					int vertexIndex = 4 * i;
					this.triangles[startIndex] = vertexIndex;
					this.triangles[startIndex + 1] = vertexIndex + 1;
					this.triangles[startIndex + 2] = vertexIndex + 2;
					this.triangles[startIndex + 3] = vertexIndex + 2;
					this.triangles[startIndex + 4] = vertexIndex + 1;
					this.triangles[startIndex + 5] = vertexIndex + 3;
				}
				this.mesh.triangles = this.triangles;
				this.mesh.RecalculateBounds();
				this.mesh.RecalculateNormals();
				this.isNeedUpdateMesh = false;
			}
		}


		private void GenterVector(int shadowCount)
        {
			if(this.shadowCount < shadowCount)
            {
				this.shadowCount = Mathf.Max(this.shadowCount * 2, shadowCount);
				this.vertices = new Vector3[4 * this.shadowCount];
				this.uv = new Vector2[4 * this.shadowCount];
            }
        }


	}
}

